package com.freedom.sql.jdbc.response;

import java.util.ArrayList;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

import com.alibaba.druid.sql.ast.statement.SQLShowTablesStatement;
import com.freedom.sql.jdbc.netty.MyNioSocketChannel;
import com.freedom.sql.jdbc.utils.BufferAllocateUtils;
import com.freedom.sql.jdbc.utils.ByteUtils;
import com.freedom.sql.jdbc.utils.LoggerUtils;
import com.freedom.sql.jdbc.utils.MyJsonProperties;

import io.netty.buffer.ByteBuf;

public class TablePacket {
	private static final Logger logger = LogManager.getLogger(TablePacket.class);
	private MyNioSocketChannel channel;
	@SuppressWarnings("unused")
	private byte[] content;
	private int packetSeq;
	private byte[] db;

	public TablePacket(int _packetSeq, MyNioSocketChannel _channel, SQLShowTablesStatement _content) {
		packetSeq = _packetSeq;
		channel = _channel;
		// content = _content.getBytes();
		db = ByteUtils.encode(channel.getDb(), channel.getCharset());
	}

	public void write() throws Exception {
		if (null == db || db.length <= 0) {
			throw new Exception("no db specified...");
		}
		LoggerUtils.debug(logger, "db is valid---" + db);
		ArrayList<String> tableList = MyJsonProperties.getInstance().getDatabases()
				.get(ByteUtils.decode(db, channel.getCharset()));
		if (null == tableList) {
			throw new Exception("no table specified...");
		}
		LoggerUtils.debug(logger, "table is as follows: " + tableList);
		String[] tables = (String[]) tableList.toArray(new String[tableList.size()]);// String[]
																						// tables
																						// =
																						// {
		// "测试表0", "测试表1",
		// "测试表2", "测试表3" };
		long begin = System.currentTimeMillis();
		int totalLength = 0;
		//
		// header
		byte[] headerLen = ByteUtils.writeInt(1, 3);
		byte[] headerPacketId = { (byte) (++packetSeq) };
		byte[] headerNumberFields = { 2 };
		totalLength += 5;
		//
		// FieldPacket
		byte[] fieldLen = ByteUtils.writeInt(82 + db.length, 3);
		byte[] fieldPacketId = { (byte) (++packetSeq) };
		byte[] fieldDetailsPrefix = { 3, 'd', 'e', 'f', // catalog
				0x12, 'i', 'n', 'f', 'o', 'r', 'm', 'a', 't', 'i', 'o', 'n', '_', 's', 'c', 'h', 'e', 'm', 'a', // db
				0x0b, 'T', 'A', 'B', 'L', 'E', '_', 'N', 'A', 'M', 'E', 'S', // table
				0x0b, 'T', 'A', 'B', 'L', 'E', '_', 'N', 'A', 'M', 'E', 'S', // orgTable
				(byte) (10 + db.length) };
		byte[] fieldDetailsMiddle = ByteUtils.union("Tables_in_".getBytes(), db);// name
		byte[] fieldDetailsSuffix = { //
				0x0a, 'T', 'A', 'B', 'L', 'E', '_', 'N', 'A', 'M', 'E', // orgName
				(byte) 0x0C, //
				33, 0, // charsetIndex->utf8
				(byte) 0xc0, 0, 0, 0, // length
				(byte) (((byte) 253) & 0xff), // type
				1, 0, // flags
				0, // decimals
				0, 0,// fill
		};
		totalLength += fieldLen.length + fieldPacketId.length + fieldDetailsPrefix.length + fieldDetailsMiddle.length
				+ fieldDetailsSuffix.length;
		// FieldPacket1
		byte[] fieldLen1 = ByteUtils.writeInt(82, 3);
		byte[] fieldPacketId1 = { (byte) (++packetSeq) };
		byte[] fieldDetails1 = { 3, 'd', 'e', 'f', // catalog
				0x12, 'i', 'n', 'f', 'o', 'r', 'm', 'a', 't', 'i', 'o', 'n', '_', 's', 'c', 'h', 'e', 'm', 'a', // db
				0x0b, 'T', 'A', 'B', 'L', 'E', '_', 'N', 'A', 'M', 'E', 'S', // table
				0x0b, 'T', 'A', 'B', 'L', 'E', '_', 'N', 'A', 'M', 'E', 'S', // orgTable
				0x0a, 'T', 'a', 'b', 'l', 'e', '_', 't', 'y', 'p', 'e', // name
				0x0a, 'T', 'A', 'B', 'L', 'E', '_', 'T', 'Y', 'P', 'E', // orgName
				(byte) 0x0C, //
				33, 0, // charsetIndex->utf8
				(byte) 0xc0, 0, 0, 0, // length
				(byte) (((byte) 253) & 0xff), // type
				1, 0, // flags
				0, // decimals
				0, 0,// fill

		};
		totalLength += fieldLen1.length + fieldPacketId1.length + fieldDetails1.length;
		//
		// 开始写 eof
		byte[] eofLen = ByteUtils.writeInt(5, 3);
		byte[] eofPacketId = { (byte) (++packetSeq) };
		byte[] eofDetails = { (byte) 0xfe, //
				0, 0,// warningCount
		};
		byte[] eofStatus = ByteUtils.writeInt(0x0022, 2);
		totalLength += 9;
		//
		// 开始构造我们需要的内容->根据表来

		ArrayList<byte[]> tableBytesList = new ArrayList<byte[]>();
		for (String table : tables) {
			byte[] tableNameBytes = ByteUtils.encode(table, channel.getCharset());
			tableBytesList.add(ByteUtils.writeInt(12 + tableNameBytes.length, 3));// 包长度
			tableBytesList.add(ByteUtils.writeInt(++packetSeq, 1));
			tableBytesList.add(new byte[] { (byte) tableNameBytes.length });
			tableBytesList.add(tableNameBytes);
			tableBytesList.add(new byte[] { 0x0a, 'B', 'A', 'S', 'E', ' ', 'T', 'A', 'B', 'L', 'E' });
		}
		for (byte[] content : tableBytesList) {
			totalLength += content.length;
		}
		//
		// 最后的eof
		byte[] lastEofLen = ByteUtils.writeInt(5, 3);
		byte[] lastEofPacketId = { (byte) (++packetSeq) };
		byte[] lastEofDetails = { (byte) 0xfe, //
				0, 0,// warningCount
		};
		byte[] lastEofstatus = ByteUtils.writeInt(0x0022, 2);
		totalLength += 9;
		// 开始合成
		ByteBuf finalBuf = BufferAllocateUtils.get(totalLength);
		finalBuf.writeBytes(headerLen);
		finalBuf.writeBytes(headerPacketId);
		finalBuf.writeBytes(headerNumberFields);

		finalBuf.writeBytes(fieldLen);
		finalBuf.writeBytes(fieldPacketId);
		finalBuf.writeBytes(fieldDetailsPrefix);
		finalBuf.writeBytes(fieldDetailsMiddle);
		finalBuf.writeBytes(fieldDetailsSuffix);

		finalBuf.writeBytes(fieldLen1);
		finalBuf.writeBytes(fieldPacketId1);
		finalBuf.writeBytes(fieldDetails1);

		finalBuf.writeBytes(eofLen);
		finalBuf.writeBytes(eofPacketId);
		finalBuf.writeBytes(eofDetails);
		finalBuf.writeBytes(eofStatus);
		for (byte[] content : tableBytesList) {
			finalBuf.writeBytes(content);
		}
		finalBuf.writeBytes(lastEofLen);
		finalBuf.writeBytes(lastEofPacketId);
		finalBuf.writeBytes(lastEofDetails);
		finalBuf.writeBytes(lastEofstatus);
		channel.writeAndFlush(finalBuf);
		long end = System.currentTimeMillis();
		LoggerUtils.info(logger, "cost " + (end - begin) + " ms");
	}
}
